package interfaces.menu.joinGame;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;

import interfaces.GUISource;
import interfaces.PropertyContent;
import interfaces.language.LanguageButton;
import interfaces.language.LanguageLabel;
import interfaces.menu.AbsMenu;
import interfaces.menu.MenuContent;
import interfaces.menu.joinGame.filters.Filter;
import interfaces.menu.joinGame.filters.FiltersContent;
import interfaces.menu.joinGame.gamesTable.GamesTable;
import interfaces.menu.joinGame.gamesTable.GamesTableEntry;
import interfaces.menu.joinGame.gamesTable.GamesTableWidget;
import interfaces.menu.joinGame.gamesTable.PlayerWidget;
import interfaces.options.TextInputError;
import interfaces.options.TextInputErrorWindow;

import logic.common.game.GameMode;
import logic.common.team.Fraction;
import logic.nodes.nodeSettings.Settings;
import main.GameCycle;
import main.InitGame;
import main.listeners.listenerClasses.LanguageListener;
import networking.GameInfoBuilder;
import networking.MasterServerInterface;

import org.fenggui.ComboBox;
import org.fenggui.Item;
import org.fenggui.appearance.LabelAppearance;
import org.fenggui.binding.render.ImageFont;
import org.fenggui.event.ButtonPressedEvent;
import org.fenggui.event.IButtonPressedListener;

import settings.FilterSettings;

import ai.AILevel;

import fileHandling.MapLoader;
import fileHandling.ProfileHandler;
import fileHandling.language.LanguageLoader;
import fileHandling.language.interfaces.JoinGameText;
import fileHandling.language.interfaces.MenuText;

public class JoinGameContent extends MenuContent {
	
	private LanguageLabel sourceLabel;
	
	private ComboBox sourceComboBox;
	private Item internetItem, networkItem;
	
	private LanguageButton newSearchButton, refreshButton, connectToIPButton, abortButton, joinButton;
	private int upperHeight, upperY, tableHeight;
	
	private GamesTable gamesTable;
	
	private LanguageButton filterApplyButton;
	private FiltersContent filtersContent;
	
	private boolean isShowingJoinButton;
	
	private LabelAppearance labelAppearance;
	
	private GameInfoBuilder gameInfoBuilder;
	private PropertyContent progressContent;
	
	private GameDetailsContent detailsContent;
	
	public JoinGameContent(AbsMenu menu) {
		super(menu);
				
		makeUpper();
		makeTable();
		makeSouth();
		
		InitGame.get().addLanguageListener(new LanguageListener() {
			@Override
			public void languageChanged() {
				changeLanguage();
			}
		});
		
		layout();
	}
	
	private void makeUpper() {
		ImageFont widgetFont = GUISource.middleFont;
		upperHeight = widgetFont.getHeight() / 3 * 4;
		upperY = getHeight() - upperHeight;
		int widgetWidth = getWidth() / 6;
		int widgetX = 0;
		
		sourceLabel = new LanguageLabel(JoinGameText.Source, widgetFont);
		sourceLabel.setSize(widgetWidth, upperHeight);
		sourceLabel.setXY(widgetX, upperY);
		addWidget(sourceLabel);
		widgetX += widgetWidth;
		
		sourceComboBox = GUISource.createComboBox(GUISource.middleFont);
		sourceComboBox.setSize(widgetWidth, upperHeight / 2);
		sourceComboBox.setXY(widgetX, upperY);
		addWidget(sourceComboBox);
		
		labelAppearance = new LabelAppearance(sourceComboBox);
		internetItem = new Item(LanguageLoader.get(JoinGameText.Internet), labelAppearance);
		networkItem = new Item(LanguageLoader.get(JoinGameText.Network), labelAppearance);
		
		sourceComboBox.addItem(internetItem);
		sourceComboBox.addItem(networkItem);
		sourceComboBox.setSelected(networkItem);
		
		widgetWidth = getWidth() / 6;
		widgetX = getWidth() - widgetWidth;
		
		connectToIPButton = new LanguageButton(JoinGameText.Connect_to_IP, widgetFont);
		connectToIPButton.addButtonPressedListener(new IButtonPressedListener() {
			@Override
			public void buttonPressed(ButtonPressedEvent e) {
				IPWindow ipWindow = new IPWindow(menu, gamesTable);
				menu.addWidget(ipWindow);
				menu.getMenuState().getGUIDisplay().setFocusedWidget(ipWindow);
			}
		});
		connectToIPButton.setSize(widgetWidth, upperHeight);
		connectToIPButton.setXY(widgetX, upperY);
		addWidget(connectToIPButton);
		widgetX -= widgetWidth;
		
		newSearchButton = new LanguageButton(JoinGameText.New_Search, widgetFont);
		newSearchButton.addButtonPressedListener(new IButtonPressedListener() {
			@Override
			public void buttonPressed(ButtonPressedEvent e) {
				gamesTable.clear();
				detailsContent.clear();
				showJoinButton(false);
				removeWidget(refreshButton);
				
//				addDummyEntries();
				
				String[] ips = null;
				if(sourceComboBox.getSelectedItem() == internetItem) 
					ips = MasterServerInterface.getActiveGames();
				else ips = getLANIPs();
				
				if(ips != null) searchIPs(ips);
			}
		});
		newSearchButton.setSize(widgetWidth, upperHeight);
		newSearchButton.setXY(widgetX, upperY);
		addWidget(newSearchButton);
		widgetX -= widgetWidth;
		
		abortButton = new LanguageButton(JoinGameText.Abort_Search, widgetFont);
		abortButton.addButtonPressedListener(new IButtonPressedListener() {
			@Override
			public void buttonPressed(ButtonPressedEvent e) {
				abortServerSearch();
			}
		});
		abortButton.setSize(widgetWidth, upperHeight);
		abortButton.setXY(widgetX, upperY);
		
		refreshButton = new LanguageButton(JoinGameText.Refresh_List, widgetFont);
		refreshButton.addButtonPressedListener(new IButtonPressedListener() {
			@Override
			public void buttonPressed(ButtonPressedEvent e) {
				refreshList();
			}
		});
		refreshButton.setSize(widgetWidth, upperHeight);
		refreshButton.setXY(widgetX, upperY);
	}
	
	private void searchIPs(String[] ips) {
		addWidget(progressContent);
		progressContent.setValue(0);
		progressContent.setMaxValue(ips.length);
		
		gameInfoBuilder = new GameInfoBuilder(ips, gamesTable, this);
		gameInfoBuilder.start();
		if(!getContent().contains(abortButton)) addWidget(abortButton);
		newSearchButton.setEnabled(false);
	}
	
	protected void addDummyEntries() {
		Random r = new Random();
		int games = 10 + r.nextInt(20);
//		int games = 1;
		List<String> availabelMaps = MapLoader.findMaps();
		GameMode[] allGameModes = GameMode.values();
		AILevel[] allAILevels = AILevel.values();
		
		String[] lanIPs = getLANIPs();
		Fraction[] fractions = Fraction.values();
		
		for(int i = 0; i < games; i++) {
			List<String> scenarios = new ArrayList<String>();
			
			int scenNumber = 1 + r.nextInt(3);
			for(int j = 0; j < scenNumber; j++) {
				scenarios.add(availabelMaps.get(r.nextInt(availabelMaps.size())));
			}
			
			GameMode mode = allGameModes[r.nextInt(allGameModes.length)];
			
			int respawn = 1 + r.nextInt(20);
			int end = 1 + r.nextInt(20);
			int maxPlayers = 1 + r.nextInt(32);
			boolean bots = r.nextBoolean();
			AILevel ai = allAILevels[r.nextInt(allAILevels.length)];
			String name = "game" + i;
			String ip = lanIPs[r.nextInt(lanIPs.length)];
			int score = 20 + r.nextInt(200);
			int tickets = 50 + r.nextInt(200);
			boolean balancedTeams = r.nextBoolean();
			boolean friendlyFire = r.nextBoolean();
			
			GameCycle gameCycle = new GameCycle(scenarios, respawn, end, maxPlayers, bots, ai, name, ip, 
					false, mode, score, tickets, balancedTeams, friendlyFire);
			
			List<PlayerWidget> players = new ArrayList<PlayerWidget>();
			int playerNumber = r.nextInt(maxPlayers);
			
			for(int j = 0; j < playerNumber; j++) {
				int playerScore = r.nextInt(400);
				Fraction fraction = fractions[r.nextInt(fractions.length)];
				String playerName = "Player" + j;
				PlayerWidget pWidget = new PlayerWidget(playerName, fraction, playerScore);
				players.add(pWidget);
			}
			
			int ping = 10 + r.nextInt(200);
			
			GamesTableWidget widget = new GamesTableWidget(gameCycle, players);
			widget.setPing(ping);
			gamesTable.addGame(widget);
		}
	}
	
	private void makeTable() {
		int orderButtonHeight = upperHeight;
		int orderButtonY = upperY - orderButtonHeight;
		
		int tableWidth = getWidth();
		tableHeight = (getHeight() - upperHeight) / 2;
		gamesTable = new GamesTable(tableWidth, tableHeight, this);
		gamesTable.setXY(0, orderButtonY - tableHeight);
		addWidget(gamesTable);
		
		int progressY = gamesTable.getY() + gamesTable.getHeight();
		int progressHeight = newSearchButton.getY() - progressY;
		progressContent = new PropertyContent(getWidth(), progressHeight, 0, progressY);
	}
	
	private String[] getLANIPs() {
		try {
			int maxIPRange = 256;
			String[] ips = new String[maxIPRange - 1];
			String localIP = InitGame.get().getThisIP();
			if(localIP == null) localIP = "192.168.1.3"; 
			String ipStart = localIP.substring(0, localIP.lastIndexOf(".") + 1);
			
			for(int i = 0; i < ips.length; i++) {
				ips[i] = ipStart + (i + 1);
			}
			
			return ips;
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	private void refreshList() {
		List<GamesTableEntry> entries = gamesTable.getTableEntries();
		
		String[] ips = new String[entries.size()];
		for(int i = 0; i < entries.size(); i++) {
			GamesTableEntry entry = entries.get(i);
			if(entry != null) {
				GamesTableWidget widget = entry.getGamesTableWidget();
				if(widget != null) ips[i] = widget.getIp();
			}
		}
		
		gamesTable.clear();
		
		searchIPs(ips);
	}
	
	public void abortServerSearch() {
		gameInfoBuilder.abort();
		removeAbortButton();
		removeProgressContent();
		checkRefreshButton();
	}
	
	private void removeAbortButton() {
		removeWidget(abortButton);
		newSearchButton.setEnabled(true);
	}
	
	private void removeProgressContent() {
		removeWidget(progressContent);
	}
	
	private void checkRefreshButton() {
		if(gamesTable.getTableEntries().isEmpty()) removeWidget(refreshButton);
		else addWidget(refreshButton);
	}
	
	public void finishSearch() {
		removeAbortButton();
		removeProgressContent();
		checkRefreshButton();
	}
	
	private void makeSouth() {
		int detailsWidth = getWidth() / 2;
		
		detailsContent = new GameDetailsContent(detailsWidth, gamesTable.getY());
		addWidget(detailsContent);
		
		joinButton = new LanguageButton(MenuText.Join_Game, GUISource.biggestFont);
		joinButton.setSize(detailsContent.getPreviewWidth(), detailsContent.getPreviewY());
		joinButton.addButtonPressedListener(new IButtonPressedListener() {
			@Override
			public void buttonPressed(ButtonPressedEvent e) {
				joinGame();
			}
		});
		
		int filtersWidth = getWidth() - detailsWidth;
		ImageFont font = GUISource.middleFont;
		filterApplyButton = new LanguageButton(JoinGameText.Apply_Filters, font);
		filterApplyButton.setSize(filtersWidth, font.getHeight());
		filterApplyButton.setX(detailsWidth);
		filterApplyButton.addButtonPressedListener(new IButtonPressedListener() {
			@Override
			public void buttonPressed(ButtonPressedEvent e) {
				TextInputError error = filtersContent.checkTextInput();
				if(error != null) {
					TextInputErrorWindow window = new TextInputErrorWindow(error, menu);
					menu.addWidget(window);
				} else {
					FilterSettings settings = FilterSettings.get();
					Settings temp = new Settings(filtersContent);
					settings.copySettings(temp, true);
					ProfileHandler.changeSettings(settings);
					applyFilters();
				}
			}
		});
		addWidget(filterApplyButton);
		
		filtersContent = new FiltersContent(filtersWidth, detailsContent.getHeight() - filterApplyButton.getHeight());
		filtersContent.setXY(detailsContent.getWidth(), filterApplyButton.getHeight());
		addWidget(filtersContent);
	}
	
	public void setSelectedGame(GamesTableWidget gameWidget) {
		showJoinButton(true);
		detailsContent.setGame(gameWidget);
	}
	
	private void showJoinButton(boolean show) {
		if(isShowingJoinButton == show) return;
		
		if(isShowingJoinButton && !show) removeWidget(joinButton);
		else if(!isShowingJoinButton && show) addWidget(joinButton);
		
		isShowingJoinButton = show;
	}
	
	public void joinGame() {
		if(!isShowingJoinButton) return;
		
		abortServerSearch();
		
		GamesTableWidget widget = gamesTable.getSelectedGameWidget();
		InitGame.get().initNewGame(false, widget.getGameCycle());
	}
	
	public void applyFilters() {
		List<GamesTableEntry> removeEntries = new ArrayList<GamesTableEntry>();
		
		for(GamesTableEntry entry : gamesTable.getTableEntries()) {
			GamesTableWidget widget = entry.getGamesTableWidget();
			for(Filter f : getFilters()) {
				if(!f.passes(widget)) {
					removeEntries.add(entry); 
					break;
				}
			}
		}
		
		for(GamesTableEntry entry : removeEntries) {
			gamesTable.removeTableEntry(entry);
		}
		
		layout();
	}
	
	public void updateProgress(int progress) {
		progressContent.setValue(progress);
	}
	
	public void changeLanguage() {
		internetItem.setText(LanguageLoader.get(JoinGameText.Internet), labelAppearance);
		networkItem.setText(LanguageLoader.get(JoinGameText.Network), labelAppearance);
	}
	
	public Collection<Filter> getFilters() { return filtersContent.getFilters(); }
}